home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 #2 / Ham Radio 2000 - Volume 2.iso / HAMV2 / TCP_IP / TNOS230S / KRNLIF.C < prev    next >
Encoding:
C/C++ Source or Header  |  1997-09-14  |  12.6 KB  |  467 lines

  1. /* @(#) $Id: krnlif.c,v 1.4 1997/09/14 14:37:46 root Exp root $ */
  2.  
  3. #ifdef linux
  4.  
  5. /*****************************************************************************/
  6.  
  7. /*
  8.  *      krnlif.c  -- directly attach a linux kernel interface.
  9.  *
  10.  *      Copyright (C) 1996  Thomas Sailer (sailer@ife.ee.ethz.ch)
  11.  *
  12.  *      This program is free software; you can redistribute it and/or modify
  13.  *      it under the terms of the GNU General Public License as published by
  14.  *      the Free Software Foundation; either version 2 of the License, or
  15.  *      (at your option) any later version.
  16.  *
  17.  *      This program is distributed in the hope that it will be useful,
  18.  *      but WITHOUT ANY WARRANTY; without even the implied warranty of
  19.  *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  20.  *      GNU General Public License for more details.
  21.  *
  22.  *      You should have received a copy of the GNU General Public License
  23.  *      along with this program; if not, write to the Free Software
  24.  *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  25.  *
  26.  * What does it?
  27.  *  This module allows WAMPES to directly attach to a Linux Kernel
  28.  *  AX.25 driver.
  29.  * Why?
  30.  *  Many drivers for Packet Radio Hardware are nowadays only provided
  31.  *  as Linux Kernel network drivers. Character KISS drivers are dying out,
  32.  *  simply because the network driver interface is much cleaner, simpler
  33.  *  and faster than the complicated line discipline stuff needed by a
  34.  *  character driver.
  35.  *  To use such an interface in Wampes, one could use the net2kiss program
  36.  *  from the ax25 utilities, that would convert such interface packets
  37.  *  to a KISS data stream on a pseudo tty. Wampes could then attach the
  38.  *  respective slave tty. This is complicated to set up, and involves
  39.  *  some overhead.
  40.  *  This module now allows Wampes to directly attach such Linux Kernel
  41.  *  interfaces.
  42.  * Example:
  43.  *  To set up Wampes with a Baycom SER12 modem, the following steps are
  44.  *  necessary.
  45.  *  In a shell:
  46.  *    insmod hdlcdrv.o
  47.  *    insmod baycom.o modem=1 iobase=0x3f8 irq=4 options=1
  48.  *  From within Wampes (or cnet):
  49.  *    attach kernel bc0
  50.  * Note:
  51.  *  the attach command automatically brings the interface into the
  52.  *  running and promiscious state. The MTU is taken from the Linux
  53.  *  interface settings, but may be changed. attach remembers the interface
  54.  *  state and restores it at detach, i.e. if you quit wampes.
  55.  *  AX.25 kernel interfaces may be loaded into memory even if Kernel
  56.  *  AX.25 is disabled.
  57.  *
  58.  * This module is Linux specific. SOCK_PACKET is the Linux way to get
  59.  * packets at the raw interface level.
  60.  *
  61.  * Modified extensively for TNOS (brian@lantz.com)
  62.  * Added capability to also link IP into the kernel with added parameter
  63.  *
  64.  */
  65.  
  66. /*lint -save -e508 -e27 -e532 -e14 -e18 -e15 -e516 -e114 */
  67. #include <sys/types.h>
  68. #include <sys/socket.h>
  69. #include <sys/ioctl.h>
  70. #include <errno.h>
  71. #include <net/if.h>
  72. #ifdef HAVE_NETINET_IF_ETHER_H
  73. #include <netinet/if_ether.h>
  74. #include <net/if_arp.h>
  75. #include <netinet/in.h>
  76. #else
  77. #include <linux/if_ether.h>
  78. #include <linux/if_arp.h>
  79. #include <linux/in.h>
  80. #endif
  81.  
  82. #undef LOCK
  83. #define    _SOCKET_H
  84. #define _SOCKADDR_H
  85. #include "global.h"
  86. #include "iface.h"
  87. /*lint -restore */
  88. #include "commands.h"
  89. #include "devparam.h"
  90. #include "trace.h"
  91. #include "hardware.h"
  92. #include "enet.h"
  93.  
  94. #define KRNLIF_MAX 16
  95.  
  96. /* kernel interface control block */
  97. struct krnlif {
  98.     struct iface *iface;
  99.  
  100.     int fd;                 /* File descriptor */
  101.  
  102.     struct mbuf *sndq;      /* Transmit queue */
  103.  
  104.     short oldflags;         /* used to restore the interrupt flags */
  105.     int proto;              /* protocol to listen for */
  106.     int promisc;            /* set interface to promiscious mode */
  107.     int class;        /* device class (for dump) */
  108.  
  109.     long rxpkts;            /* receive packets */
  110.     long txpkts;            /* transmit packets */
  111.     long rxchar;            /* Received characters */
  112.     long txchar;            /* Transmitted characters */
  113. };
  114.  
  115. static struct krnlif KrnlIf[KRNLIF_MAX];
  116.  
  117.  
  118. static void krnlif_rx(int dev, void *v1, void *v2);
  119.  
  120.  
  121. /*---------------------------------------------------------------------------*/
  122.  
  123. static int krnlif_up(struct krnlif *ki)
  124. {
  125. struct ifreq ifr;
  126. struct sockaddr sa;
  127. char *cp;
  128.  
  129.     if (ki->fd >= 0)        /* Already UP */
  130.         return 0;
  131.     if ((ki->fd = socket(PF_INET, SOCK_PACKET, ki->proto)) < 0)
  132.         goto Fail;
  133.     strcpy(ifr.ifr_name, ki->iface->name);
  134.     if (ioctl(ki->fd, SIOCGIFFLAGS, &ifr) < 0)
  135.         goto Fail;
  136.     ki->oldflags = ifr.ifr_flags;
  137.     ifr.ifr_flags |= IFF_UP;
  138.     if (ki->promisc)
  139.         ifr.ifr_flags |= IFF_PROMISC;
  140.     if (ioctl(ki->fd, SIOCSIFFLAGS, &ifr) < 0)
  141.         goto Fail;
  142.     strcpy(sa.sa_data, ki->iface->name);
  143.     sa.sa_family = AF_INET;
  144.     if (bind(ki->fd, &sa, sizeof(struct sockaddr)) < 0)
  145.         goto Fail;
  146.  
  147.     register_io (ki->fd, &ki->fd);
  148.  
  149.     cp = if_name (ki->iface, " rx");
  150.     ki->iface->rxproc = newproc (cp, 768, krnlif_rx, ki->iface->dev, ki->iface, NULL, 0);
  151.     ki->iface->rxproc->ptype = PTYPE_IO;
  152.  
  153.     return 0;
  154.  
  155.  Fail:
  156.     if (ki->fd >= 0) {
  157.         close(ki->fd);
  158.         ki->fd = -1;
  159.     }
  160.     return -1;
  161. }
  162.  
  163. /*---------------------------------------------------------------------------*/
  164.  
  165. static int krnlif_down(struct krnlif *ki)
  166. {
  167. struct ifreq ifr;
  168.  
  169.     if (ki->fd < 0)         /* Already DOWN */
  170.         return 0;
  171.  
  172.     unregister_io (ki->fd);
  173.     free_q(&ki->sndq);
  174.     strcpy(ifr.ifr_name, ki->iface->name);
  175.     ifr.ifr_flags = ki->oldflags;
  176.     (void) ioctl(ki->fd, SIOCSIFFLAGS, &ifr);
  177.     killproc (ki->iface->rxproc);
  178.     ki->iface->rxproc = NULLPROC;
  179.     close(ki->fd);
  180.     ki->fd = -1;
  181.     return 0;
  182. }
  183.  
  184. /*---------------------------------------------------------------------------*/
  185.  
  186. /* Asynchronous line I/O control */
  187.  
  188. static int32 krnlif_ioctl(struct iface *ifp, int cmd, int set OPTIONAL, int32 val OPTIONAL)
  189. {
  190. struct krnlif *ki;
  191.  
  192.     if (!ifp || ifp->dev < 0 || ifp->dev >= KRNLIF_MAX)
  193.         return -1;
  194.     ki = KrnlIf + ifp->dev;
  195.  
  196.     switch(cmd){
  197.         case PARAM_DOWN:
  198.             return krnlif_down(ki) ? 0 : 1;
  199.         case PARAM_UP:
  200.             return krnlif_up(ki) ? 0 : 1;
  201.         default:
  202.             return -1;
  203.     }
  204. }
  205.  
  206. /*---------------------------------------------------------------------------*/
  207.  
  208. static int krnlif_raw(struct iface *iface, struct mbuf *bp)
  209. {
  210. struct krnlif *ki;
  211. struct sockaddr to;
  212. uint8 buf[4096]; /* should be enough */
  213. uint8 *bufp = buf;
  214. struct mbuf *bp2;
  215. int cnt = 0;
  216. int i;
  217.  
  218.     ki = KrnlIf + iface->dev;
  219.     dump (iface, IF_TRACE_OUT, (unsigned) ki->class, bp);
  220.  
  221.     iface->rawsndcnt++;
  222.     iface->lastsent = secclock();
  223.     if (iface->trace & IF_TRACE_RAW)
  224.         raw_dump(iface, -1, bp);
  225.     if (iface->dev < 0 || iface->dev >= KRNLIF_MAX){
  226.         free_p (bp);
  227.         return -1;
  228.     }
  229.  
  230.     if (ki->iface == NULL || ki->fd < 0)
  231.         free_p (bp);
  232.     else {
  233.         for (bp2 = bp; bp2; bp2 = bp2->next) {
  234.             cnt += bp2->cnt;
  235.             if (cnt > (int) sizeof(buf)) {
  236.                 (void) free_mbuf (bp);
  237.                 return -1;
  238.             }
  239.             memcpy (bufp, bp2->data, bp2->cnt);
  240.             bufp += bp2->cnt;
  241.         }
  242.         strncpy(to.sa_data, ki->iface->name, sizeof(to.sa_data));
  243.             
  244.         i = sendto(ki->fd, buf, (unsigned) cnt, 0, &to, sizeof(to));
  245.  
  246.         if (i >= 0) {
  247.             ki->txpkts++;
  248.             ki->txchar += i;
  249.             (void) free_mbuf(bp);
  250.             return 0;
  251.         }
  252.         if (errno == EMSGSIZE) {
  253.             (void) free_mbuf(bp);
  254.             return -1;
  255.         }
  256.         if (errno == EWOULDBLOCK)
  257.             return 0;
  258.         (void) krnlif_down(ki);
  259.     }
  260.     return 0;
  261. }
  262.  
  263. /*---------------------------------------------------------------------------*/
  264.  
  265. static void krnlif_rx (int dev OPTIONAL, void *v1, void *v2 OPTIONAL)
  266. {
  267. struct iface *iface = (struct iface *) v1;
  268. struct krnlif *ki;
  269. struct sockaddr from;
  270. int from_len = sizeof(from);
  271. int i;
  272. struct mbuf *bp;
  273.  
  274.     server_disconnect_io ();
  275.     if (!iface || iface->dev < 0 || iface->dev >= KRNLIF_MAX)
  276.         return;
  277.     ki = KrnlIf + iface->dev;
  278.  
  279.     for ( ; ; )    {
  280.         kwait (&ki->fd);
  281.         if ((bp = alloc_mbuf(ki->iface->mtu+16)) == 0)
  282.             return;
  283.         i = recvfrom(ki->fd, bp->data, bp->size, 0, &from, &from_len);
  284.         if (i <= 0) {
  285.             if (i < 0 || errno != EWOULDBLOCK)
  286.                 (void) krnlif_down(ki);
  287.             (void) free_mbuf(bp);
  288.             ki->iface->rxproc = NULLPROC;
  289.             return;
  290.         }
  291.         bp->cnt = (int16) i;
  292.         ki->rxpkts++;
  293.         ki->rxchar += i;
  294.         if (ki->iface->trace & IF_TRACE_RAW)
  295.             raw_dump(ki->iface, IF_TRACE_IN, bp);
  296.  
  297.         (void) net_route(ki->iface, ki->class, bp);
  298.     }
  299. }
  300.  
  301. /*---------------------------------------------------------------------------*/
  302.  
  303. static void krnlif_status(struct iface *iface)
  304. {
  305.     struct krnlif *ki;
  306.  
  307.     if (!iface || iface->dev < 0 || iface->dev >= KRNLIF_MAX)
  308.         return;
  309.     ki = KrnlIf + iface->dev;
  310.     if (ki->iface != iface)
  311.         return;
  312.  
  313.     tprintf("           Received:    Packets %8ld Chars %8ld\n"
  314.            "           Transmitted: Packets %8ld Chars %8ld\n",
  315.            ki->rxpkts, ki->rxchar, ki->txpkts, ki->txchar);
  316. }
  317.  
  318. /*---------------------------------------------------------------------------*/
  319.  
  320. static int krnlif_detach(struct iface *ifp)
  321. {
  322.     struct krnlif *ki;
  323.  
  324.     if (ifp == NULL)
  325.         return -1;
  326.     if (ifp->dev < 0 || ifp->dev >= KRNLIF_MAX)
  327.         return -1;
  328.     ki = KrnlIf + ifp->dev;
  329.     if(ki->iface == NULL)
  330.         return -1;      /* Not allocated */
  331.     (void) krnlif_down(ki);
  332.     ki->iface = NULL;
  333.     return 0;
  334. }
  335.  
  336. /*---------------------------------------------------------------------------*/
  337.  
  338. static struct hwencap {
  339.     unsigned short family;
  340.     char const *encap;
  341.     int class;
  342. } hwencap[] = {
  343. #ifdef NETROM
  344.     { ARPHRD_NETROM,        "NETROM",    16  /* CL_NETROM */ },
  345. #endif
  346.     { ARPHRD_ETHER,         "Ethernet",    1   /* CL_ETHERNET */ },
  347. #ifdef KISS
  348.     { ARPHRD_AX25,          "AX25",        9   /* CL_AX25 */ },
  349. #endif
  350. #ifdef ARPHRD_LOOPBACK
  351.     { ARPHRD_LOOPBACK,    "None",        0   /* CL_NONE */ },
  352. #endif
  353.     { 0,                    0,        0 }
  354. };
  355.  
  356. int krnlif_attach(int argc, char *argv[], void *p OPTIONAL)
  357. {
  358. struct iface *ifp;
  359. int dev;
  360. struct krnlif *ki;
  361. struct ifreq ifr;
  362. struct sockaddr hw;
  363. struct sockaddr_in in;
  364. int fd;
  365. struct hwencap *hwe = hwencap;
  366.  
  367.     if (if_lookup(argv[1]) != NULL) {
  368.         tprintf("Interface %s already exists\n",argv[4]);
  369.         return -1;
  370.     }
  371.     /*
  372.      * get parameters of the interface
  373.      */
  374.     if ((fd = socket(PF_INET, SOCK_PACKET, htons(ETH_P_ALL))) < 0) {
  375.         tprintf ("socket error: %s\n", strerror (errno));
  376.         return -1;
  377.     }
  378.     strncpy(ifr.ifr_name, argv[1], sizeof(ifr.ifr_name));
  379.     ifr.ifr_addr.sa_family = AF_INET;
  380.     if (ioctl(fd, SIOCGIFADDR, &ifr) < 0) {
  381.         tprintf ("ioctl error (SIOCGIFADDR): %s\n", strerror (errno));
  382.         tprintf("cannot get inet addr for interface %s\n", argv[1]);
  383.         return -1;
  384.     }
  385.     if (ifr.ifr_addr.sa_family != AF_INET) {
  386.         tprintf("Interface %s: not AF_INET, %d\n", argv[1],
  387.                ifr.ifr_addr.sa_family);
  388.         return -1;
  389.     }
  390.     memcpy(&in, &ifr.ifr_addr, sizeof(in));
  391.     ifr.ifr_addr.sa_family = AF_UNSPEC;
  392.     if (ioctl(fd, SIOCGIFADDR, &ifr) < 0) {
  393.         tprintf ("ioctl error (SIOCGIFADDR): %s\n", strerror (errno));
  394.         tprintf("cannot get hw addr for interface %s\n", argv[1]);
  395.         return -1;
  396.     }
  397.     hw = ifr.ifr_hwaddr;
  398.     for (; (hwe->family != hw.sa_family) && (hwe->encap != NULL); hwe++)
  399.         ;
  400.     if (hwe->family != hw.sa_family) {
  401.         tprintf("Interface %s: invalid ARP type %d\n", argv[1],
  402.                hw.sa_family);
  403.         return -1;
  404.     }
  405.     if (ioctl(fd, SIOCGIFMTU, &ifr) < 0) {
  406.         tprintf ("ioctl error (SIOCGIFMTU): %s\n", strerror (errno));
  407.         tprintf("cannot get mtu for interface %s\n", argv[1]);
  408.         return -1;
  409.     }
  410.  
  411.     /* Find unused krnlif control block */
  412.     for (dev=0; (dev < KRNLIF_MAX) && (KrnlIf[dev].iface); dev++)
  413.         ;
  414.     if (dev >= KRNLIF_MAX){
  415.         tprintf("Too many kernel interfaces\n");
  416.         return -1;
  417.     }
  418.     ki = KrnlIf+dev;
  419.     /* Create interface structure and fill in details */
  420.     ifp = (struct iface *)callocw(1,sizeof(struct iface));
  421.     ifp->addr = Ip_addr /*in.sin_addr.s_addr*/;
  422.     ifp->name = strdup(argv[1]);
  423.     ifp->mtu = (int16) ifr.ifr_mtu;
  424.     ifp->dev = dev;
  425.     ifp->stop = krnlif_detach;
  426.     /* set encapsulation */
  427.     (void) setencap(ifp, hwe->encap);
  428.     ki->class = hwe->class;
  429.     ifp->ioctl = krnlif_ioctl;
  430.     ifp->raw = krnlif_raw;
  431.     ifp->show = krnlif_status;
  432.     ifp->xdev = dev;
  433.     
  434.     /* set hwaddr */
  435.     switch (hw.sa_family)    {
  436.         case ARPHRD_AX25:    if (ifp->hwaddr == NULL)
  437.                         ifp->hwaddr = (char *) mallocw(AXALEN);
  438.                     memcpy(ifp->hwaddr, Mycall, AXALEN);
  439.                     ki->proto = htons(ETH_P_AX25);
  440.                     ki->promisc = !((argc >= 3) && !strcmp(argv[2], "nopromisc"));;
  441.                     break;
  442.         case ARPHRD_LOOPBACK:
  443.         case ARPHRD_ETHER:
  444.         default:
  445.                     ifp->hwaddr = mallocw (ETHERLEN);
  446.                     memcpy (ifp->hwaddr, hw.sa_data, ETHERLEN);
  447.                     ki->proto = htons(ETH_P_ALL);
  448.                     ki->promisc = 1;
  449.                     break;
  450.     }
  451.  
  452.     close (fd);
  453.     ki->fd = -1;
  454.     ki->iface = ifp;
  455.  
  456.     /* Link in the interface */
  457.     ifp->next = Ifaces;
  458.     Ifaces = ifp;
  459.  
  460.     return krnlif_up(ki);
  461. }
  462.  
  463. /*---------------------------------------------------------------------------*/
  464.  
  465.  
  466. #endif
  467.